#encoding=utf-8
#author=GreySign
#date=2010-6-26
#file=outputhandle.py
#version=1.0
#封装了print 和 logging ，可以方便记录日志和打印调试信息。
#update:
#       2010-7-29 加入了错误跟踪信息的打印和日志记录

import logging
import traceback,sys,StringIO

def initLog(logfile, level):
    '''日志记录函数，日志等级默认为2，即INFO级别的日志'''
    
    logLevel = logging.INFO
    if level == 0:
        logLevel = logging.NOTSET
    elif level == 1:
        logLevel = logging.DEBUG
    elif level == 2:
        logLevel = logging.INFO
    elif level == 3:
        logLevel = logging.WARNING
    elif level == 4:
        logLevel = logging.ERROR
    elif level == 5:
        logLevel = logging.CRITICAL
    logger = logging.getLogger()
    console = logging.FileHandler(logfile)
    formatter = logging.Formatter(\
        '[%(asctime)s]%(filename)s-%(process)d-%(thread)d-%(lineno)d-%(levelname)8s-"%(message)s"'\
        ,'%Y-%m-%d %a %H:%M:%S')
    console.setFormatter(formatter)
    logger.addHandler(console)
    logger.setLevel(logLevel)
    return logger



########################################################################
class DebugHandle:
    """"""

    #----------------------------------------------------------------------
    def __init__(self,logfile='debug_handle.log',loglevel=1,printer_level=1):
        """Constructor"""
        self._logger = initLog(logfile, loglevel)
        self.printer_level = printer_level
        
    
    
    def printer(self,*info,**kw):
        ''' 
        打印接口.
        会将信息输出到log file，屏幕。
        错误（warning、error）信息会有跟踪信息进行打印和记录。
        eg:
        printer('hi','knownsec!',ltype='warning',noinvoke=True,pl=1)
        ltype、noinvoke可选
        1.ltype默认为info日志级别，出错时可用warning跟error
        2.noinvoke默认打印调用者信息，可设置True让打印时不显示调用者信息
        3.pl为打印级别（print level），0级最高，命令行参数可指定打印的级别。0级为绝对会输出的内容。
          0>1>2
          默认不指定pl级别的输入，都是1级。
          例如指定打印2级输出，就会打印包括0、1、2级别的输出信息。
          最低等级为2，默认全局指定的打印等级为2，即打印0、1、2（全部）级别的日志。
        '''
        
        noinvoke = False
        pl = 1
        if kw: 
            try:
                if kw['ltype'].lower() == 'warning' or kw['ltype'].lower() == 'error':
                    ltype = kw['ltype']
            except:
                ltype = False
            #不打印调用者信息
            noinvoke = kw.get('noinvoke',False)
            #打印等级
            pl = kw.get('pl',1)
        else:
            ltype = False
        s =  traceback.extract_stack()
        invoke = str(s[-2][2])
        info = map(str,info)
        #logging....
        if ltype:
            wrong_logger = getattr(self._logger,ltype)
            err_info = '-' * 30 + '\n'
            fp = StringIO.StringIO()    #创建内存文件对象
            traceback.print_exc(file=fp)
            message = fp.getvalue()
            err_info += message
            err_info += '-' * 30 + '\n'
            wrong_logger('[!]%s() : %s\n%s'%(invoke,' '.join(info),err_info))
        else:
            self._logger.info('[*]%s() : %s'%(invoke,' '.join(info)))
        #printing....
        if __debug__ and not noinvoke and pl <= self.printer_level:
            print '[*]'+invoke+'() :',
        if __debug__ and pl <= self.printer_level:
            for i in info:
                print i,
            print #回车
            #假如是warning、error，打印出错信息
            if ltype: 
                print '-' * 30
                print message + '-' * 30


def testme():
    dh = DebugHandle(logfile='debug_handle_test.log',loglevel=1,printer_level=2)
    printer = dh.printer
    printer('this is test ,debughandle...\nlogging ok,\nprint ok\ncheck debug_handle_test.log!')

    